#ifndef cope_queue_h
#define cope_queue_h

#include "priqueue.h"
#include "dsr-priqueue.h"
#include "virqueue.h"
#include "cope.h"
#include <list>
#include <algorithm>
using std::list;

#define RETRANSMIT_TIMES   2
/*
 * Additional macro definition for insert packet at the head of CMUPriQueue
 * to retransmit. The rest macro definitions are in dsr-priqueue.h. 
 */
struct ifqueue;

#define IF_ENQUEUE_HEAD(ifq, p) {		\
	if(!((ifq)->ifq_head))			\
	    (ifq)->ifq_tail = (p);		\
	(p)->next_ = (ifq)->ifq_head;		\
	(ifq)->ifq_head = (p);			\
	(ifq)->ifq_len ++;			\
    }
/*
 * Additional macro definition for delete an arbitrary item from CMUPriQueue,
 * res_p is de dequeued packet
 */

#define IF_DEQUE_ITEM(ifq, field, p, res_p) {			\
	field * iter =  (ifq)->ifq_head;			\
	field * prev_iter = iter;				\
	while( iter != 0 ) {					\
	    if(HDR_CMN(iter)->uid_ == HDR_CMN(p)->uid_) {	\
		if(iter == (ifq)->ifq_head) {			\
		    IF_DEQUEUE((ifq), res_p);			\
		} else if(iter == (ifq)->ifq_tail){		\
		    res_p = (ifq)->ifq_tail;			\
		    (ifq)->ifq_tail = prev_iter;		\
		    prev_iter->next_ = 0;			\
		    (ifq)->ifq_len--;				\
		} else {					\
		    prev_iter->next_ = iter->next_;		\
		    iter->next_ = 0;				\
		    res_p = iter;				\
		    (ifq)->ifq_len--;				\
		}						\
		break;						\
	    }							\
	    prev_iter = iter;					\
	    iter = iter->next_;					\
	}							\
    }						

    
#define IF_EMPTY(ifq, empty) {			\
	empty = false;				\
	if((ifq)->ifq_len == 0)			\
	    empty = true;			\
    }


class COPE;
class COPEHandler;

/* /\* ====================================================================== */
/*                             COPEHandler */
/* 			    =========== */
/*                     Handles callbacks for COPE */
/*    ====================================================================== *\/ */
/* class COPEPriQueueHandler : public CMUPriQueueHandler, public QueueHandler { */
/*  public: */
/*   inline COPEPriQueueHandler() : CMUPriQueueHandler(this), */
/*     QueueHandler(this) { */

/*     } */
/*   void setCOPE(COPE * cope_inst){cope_inst_ = cope_inst;} */
/*     void virtual handle(Event*); */
/*  private:  */
/*     COPE * cope_inst_; */
/* }; */

/* ======================================================================
   COPEPriQueue
   ============
   This is an output queue multi-inherit from CMUPriQueue and PriQueue,
   it is more like an assistant of COPE than a real interface queue, since
   it no longer receives any packet from LL or mac directly, and only
   created as an instance member within COPE.

   But it is still a queue, which will maintain all packets sent down
   from LL and appoint differnet running methods according to different 
   routing protocols. It encapsulate CMUPriQueue and PriQueue.

   The main difference from two parents is that it adds some COPE operation,
   like encoding or decoding etc. by calling COPE instance's algorithm,
   ====================================================================== */   
 
class COPEPriQueue : public CMUPriQueue, public PriQueue {
 public:
    COPEPriQueue();
    ~COPEPriQueue();
    
    /************ Public Functions **************/
    
    /*
     * handle command "cope-init" and "up-target"
     */
    int command(int argc, const char*const* argv);
    
    /*
     * call CMUPriqueue's drop or PriQueue's drop according to dsr_
     */
    void drop(Packet *);
    
    /*
     * called by cope_resume(), used to resume a dequeue and encode algorithm
     */
    void cope_prq_resume(COPE * ); 
  
    /*
     * Send the packet downside, the native packets could be encoded here
     */ 
    void cope_prq_senddown(Packet*, COPE* );
    
    /*
     * Enqueue the packet into queue, bool can decide enqueTail or enqueHead 
     */
    void cope_enqueue(Packet*, bool, COPE*);

    /* 
     * Dequeue an arbitrary item from cope queue
     */
    Packet * cope_dequeue_item(Packet * /* p */);

    bool cope_lookup_item(Packet * /* p */);
   
    void showQueue(COPE*);

    void setCOPEHandler(COPEHandler * );

    void resume();
    void prq_resume(void);

    bool isEmpty();

    /************ Public Variables **************/

    /*
     * virtual queue should be construct with a output queue order,
     * and indexed by next hop 
     */
    VirQueue * cope_vir_table_;

    
 
    NsObject* up_target_; // an uptarget of ifq, to simulate BiConnector
    NsObject* down_target_;
    int dsr_ ; // indicate DSR protocol or not
    
 private:

    /************ Private Functions **************/

    /*
     * To calculate the RRT time to set the timer time-out.
     */
    double txtime(Packet * , COPE * );

    /*
     * This function should be only used to handle enqueue packets the COPE
     * sent out.
     */
    void enqueue_non_ack(int nodeid, Packet* p);
    
    /*
     * receive a high priority packet, only for PriQueue, will call
     * encode functions inside
     */
    void recvHighPriority(Packet*, COPE * );

    /*
     * receive a normal packet, also only for PriQueue, will call
     * encode functions inside
     */
    void recvNormalPriority(Packet*, COPE * );
    
    /*
     * integrate all encode algorithm together
     */
    int cope_prq_encode(Packet * ,COPE * , Packet **, Packet** );

    // get this packet's priority
    int prq_assign_queue(Packet *p);

    //
    Packet * prq_dequeue();

    /************ Private Variables **************/

    //    int dsr_ ; // indicate DSR protocol or not
    COPEHandler * h_cope_;
  
};

#endif
